﻿using System;
using System.Collections.Generic;
using System.IO;

namespace ThoughtWorks
{
    public class HotelReservation
    {
        public const string Lakewood = "Lakewood";
        public const string Bridgewood = "Bridgewood";
        public const string Ridgewood = "Ridgewood";

        private readonly string[] AllDays = {"mon", "tues", "wed", "thur", "fri", "sat", "sun"};
        private readonly Dictionary<string, DayType> DaysDict = new Dictionary<string, DayType>();
        private readonly Dictionary<string, Hotel> HotelsDict = new Dictionary<string, Hotel>();

        public HotelReservation()
        {
            var lakewood = new Hotel(Lakewood, 3, 100, 80, 90, 80);
            var bridgewood = new Hotel(Bridgewood, 4, 160, 110, 60, 50);
            var ridgewood = new Hotel(Ridgewood, 5, 220, 100, 150, 40);
            HotelsDict.Add(Lakewood, lakewood);
            HotelsDict.Add(Bridgewood, bridgewood);
            HotelsDict.Add(Ridgewood, ridgewood);
            foreach (string day in AllDays)
            {
                if ("sun" == day.ToLower().Trim() || "sat" == day.ToLower().Trim())
                {
                    DaysDict.Add(day, DayType.Weekend);
                }
                else
                {
                    DaysDict.Add(day, DayType.Weekday);
                }
            }
        }

        internal string CalculateBestChoise(string testDataPath)
        {
            var reader = new StreamReader(testDataPath);
            string data = reader.ReadToEnd();
            CustomerType customerType = GetCustomerType(data);
            List<DayType> dayTypes = GetDayTypes(data);
            var allPrice = new Dictionary<string, int>();
            foreach (Hotel hotel in HotelsDict.Values)
            {
                int price = CalculatePrice(hotel, customerType, dayTypes);
                allPrice.Add(hotel.Name, price);
            }
            return MakeFinalJustWithRating(allPrice);
        }

        private string MakeFinalJustWithRating(Dictionary<string, int> allPrice)
        {
            int min = Int32.MaxValue;
            string name = "";
            foreach (string key in allPrice.Keys)
            {
                if (min > allPrice[key])
                {
                    name = key;
                    min = allPrice[key];
                }
                else if (min == allPrice[key] && RatingHigher(key, name))
                {
                    name = key;
                    min = allPrice[key];
                }
            }
            return name;
        }

        private bool RatingHigher(string hotelone, string hoteltwo)
        {
            if (HotelsDict[hotelone].Rating > HotelsDict[hoteltwo].Rating)
                return true;
            return false;
        }

        private int CalculatePrice(Hotel hotel, CustomerType customerType, List<DayType> dayTypes)
        {
            int sum = 0;
            foreach (DayType day in dayTypes)
            {
                if (DayType.Weekday == day)
                {
                    if (CustomerType.Regular == customerType)
                    {
                        sum += hotel.RegularWeekday;
                    }
                    else
                    {
                        sum += hotel.RewardsWeekday;
                    }
                }
                else
                {
                    if (CustomerType.Regular == customerType)
                    {
                        sum += hotel.RegularWeekend;
                    }
                    else
                    {
                        sum += hotel.RewardsWeekend;
                    }
                }
            }
            return sum;
        }

        private List<DayType> GetDayTypes(string data)
        {
            var result = new List<DayType>();
            int firstindex = data.IndexOf('(');
            if (-1 == firstindex)
                return result;
            int secondindex = data.IndexOf(')', firstindex);
            if (-1 == secondindex)
                return result;
            string day = "";
            while (secondindex > firstindex)
            {
                day = data.Substring(firstindex + 1, secondindex - firstindex - 1);
                string key = day.ToLower().Trim();
                if (DaysDict.ContainsKey(key))
                {
                    result.Add(DaysDict[key]);
                }
                else
                {
                    throw new Exception("Can not parse day type:" + day);
                }
                firstindex = data.IndexOf('(', secondindex);
                if (-1 == firstindex)
                    break;
                secondindex = data.IndexOf(')', firstindex);
                if (-1 == secondindex)
                    break;
            }
            return result;
        }

        private CustomerType GetCustomerType(string data)
        {
            int index = data.IndexOf(':');
            string customerType = data.Substring(0, index);
            if ("regular" == customerType.ToLower().Trim())
                return CustomerType.Regular;
            else if ("rewards" == customerType.ToLower().Trim())
                return CustomerType.Rewards;
            else
            {
                throw new Exception("Can not parse customer type:" + customerType);
            }
        }

        #region Nested type: CustomerType

        private enum CustomerType
        {
            Regular,
            Rewards
        }

        #endregion

        #region Nested type: DayType

        private enum DayType
        {
            Weekday,
            Weekend
        }

        #endregion
    }

    public class Hotel
    {
        public Hotel(string name, int rating, int regularWeekday, int rewardsWeekday, int regularWeekend,
                     int rewardsWeekend)
        {
            Name = name;
            Rating = rating;
            RegularWeekday = regularWeekday;
            RewardsWeekday = rewardsWeekday;
            RegularWeekend = regularWeekend;
            RewardsWeekend = rewardsWeekend;
        }

        public string Name { get; set; }
        public int Rating { get; set; }
        public int RegularWeekday { get; set; }
        public int RegularWeekend { get; set; }
        public int RewardsWeekday { get; set; }
        public int RewardsWeekend { get; set; }
    }
}